package com.charles.service;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.charles.entity.IdBlock;
import com.charles.entity.UId;
import com.charles.mapper.UIdMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @author charles
 * @date 2022/11/6 0:41
 */
@Service
@Slf4j
public class IdBlockService {

    @Value("${retry.times:3}")
    private Integer retryTimes;

    @Value("${fetch.blockSize:100}")
    private Integer blockSize;

    @Autowired
    private UIdMapper uIdMapper;

    @Transactional(isolation = Isolation.READ_COMMITTED)
    public IdBlock getIdBlock(String bizType) {
        // 获取nextTinyId的时候，有可能存在version冲突，需要重试
        for (int i = 0; i < retryTimes; i++) {
            List<UId> tinyIdInfos = uIdMapper.selectList(new QueryWrapper<UId>().eq("biz_type", bizType));
            if (tinyIdInfos.size() == 0) {
                throw new RuntimeException("can not find bizType:" + bizType);
            }
            UId appIdInfo = tinyIdInfos.get(0);
            Long oldValue = appIdInfo.getNextId();
            Long newMaxId = appIdInfo.getNextId() + blockSize;
            appIdInfo.setNextId(newMaxId);
            appIdInfo.setUpdateTime(new Date());
            int row = uIdMapper.updateById(appIdInfo);
            if (row == 1) {
                IdBlock idBlock = new IdBlock(new AtomicLong(oldValue), newMaxId - 1);
                log.info("getNextSegmentId success tinyIdInfo:{} current:{}", appIdInfo, idBlock);
                return idBlock;
            } else {
                log.info("getNextSegmentId conflict tinyIdInfo:{}", appIdInfo);
            }
        }
        throw new RuntimeException("get next segmentId conflict");

    }
}
